package com.wanjia.bpsapi.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wanjia.bpsapi.constant.CalType;
import com.wanjia.bpsapi.exception.ControllerException;
import com.wanjia.bpsapi.exception.DatabaseException;
import com.wanjia.bpsapi.exception.DefaultDataNotFoundException;
import com.wanjia.bpsapi.mapper.*;
import com.wanjia.bpsapi.pojo.dto.BaseClientOffer;
import com.wanjia.bpsapi.pojo.dto.GetOffers;
import com.wanjia.bpsapi.pojo.dto.ParamNeed;
import com.wanjia.bpsapi.pojo.dto.PutAwayData;
import com.wanjia.bpsapi.pojo.dto.jkmc.UserVege;
import com.wanjia.bpsapi.pojo.entity.*;
import com.wanjia.bpsapi.service.IBaseClientService;
import com.wanjia.bpsapi.service.IParamService;
import com.wanjia.bpsapi.service.jkmc.JkAsyncService;
import com.wanjia.bpsapi.service.jkmc.JkService;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

import static com.wanjia.bpsapi.constant.Constant.*;

/**
 * <p>
 * 报价信息表 服务实现类
 * </p>
 *
 * @author wyn
 * @since 2023-02-13
 */
@Service
public class BaseClientServiceImpl extends ServiceImpl<BaseClientMapper, BaseClient> implements IBaseClientService {


    @Setter(onMethod_ = @Autowired)
    private BaseClientMapper mapper;

    @Setter(onMethod_ = @Autowired)
    private PutClientMapper putClientMapper;

    @Setter(onMethod_ = @Autowired)
    private DefaultDataMapper defaultDataMapper;

    @Setter(onMethod_ = @Autowired)
    private WjProductOfferMapper wjProductOfferMapper;

    @Setter(onMethod_ = @Autowired)
    private WjUserMapper userMapper;

    @Setter(onMethod_ = @Autowired)
    private JkService jkService;

    @Setter(onMethod_ = @Autowired)
    private JkAsyncService jkAsyncService;

    @Setter(onMethod_ = @Autowired)
    private IParamService paramService;


    @Override
    public List<BaseClientOffer> getOffers(GetOffers go) {
        long now = System.currentTimeMillis();
        if (CollUtil.isNotEmpty(go.getParamIds())) {
            Collections.sort(go.getParamIds());
        }
        if (StrUtil.isEmpty(go.getOrderBy())) {
            // 未过期在前，已过期在后
            go.setOrderBy("if(wpo.add_time * 1000 + wpo.validity_day * 24 * 60 * 60 * 1000 > " + now + ", 0, 1) asc," +
                    // 未过期按照价格升序
                    "if(wpo.add_time * 1000 + wpo.validity_day * 24 * 60 * 60 * 1000 > " + now + ", bc.offer, 0) asc," +
                    // 已过期按照时间降序
                    "wpo.add_time * 1000 + wpo.validity_day * 24 * 60 * 60 * 1000 desc");
        }
        List<BaseClientOffer> list = mapper.getOffers(go);

        //计算填充预估价格
        DefaultData defaultData = defaultDataMapper.selectByUid(go.getUid());
        if (defaultData == null || defaultData.getGross() == null
                || defaultData.getDiscount() == null || defaultData.getBusinessExpense() == null) {
            throw new DefaultDataNotFoundException();
        } else {
            List<ParamNeed> list1 = paramService.getList(go.getParamIds().toArray(new Long[0]), go.getVegeId());
            boolean containYuanPerOne = list1.stream()
                    .anyMatch(pn -> Objects.equals(pn.getCaltype(), CalType.YUAN_PRE_ONE.code()));


            list.forEach(o -> {
                //  成本/（1-利润率）* (1+商务费)
                BigDecimal putOffer = o.getOffer()
                        .multiply(BigDecimal.valueOf(100).add(defaultData.getBusinessExpense()))
                        .divide(BigDecimal.valueOf(100).subtract(defaultData.getGross()), BIG_DECIMAL_SCALE, RoundingMode.HALF_UP);
                o.setPutOffer(putOffer.toPlainString());
                o.setPutOfferByKg(containYuanPerOne ? putOffer :
                        putOffer.divide(BigDecimal.valueOf(1000), BIG_DECIMAL_SCALE, RoundingMode.HALF_UP));
            });
        }

        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public void putAway(PutAwayData data) {
        // 获取计算数据
        BaseClient baseClient = mapper.selectById(data.getId());
        if (baseClient == null) {
            throw new DatabaseException("无效的预估价格id");
        }
        Long clientId = baseClient.getClientId();
        Long vegeId = baseClient.getVegeId();
        Long wjProductOfferId = baseClient.getWjProductOfferId();
        WjUser user = userMapper.selectById(clientId);

        Long[] paramIds = Optional.of(baseClient)
                .map(BaseClient::getCost)
                .map(cost -> JSONUtil.toList(cost, Long.class))
                .orElseGet(ArrayList::new)
                .toArray(new Long[0]);
        List<ParamNeed> list1 = paramService.getList(paramIds, baseClient.getVegeId());
        boolean containYuanPerOne = list1.stream()
                .anyMatch(pn -> Objects.equals(pn.getCaltype(), CalType.YUAN_PRE_ONE.code()));

        // 校验已有数据
        QueryWrapper<PutClient> putClientQueryWrapper = new QueryWrapper<>();
        putClientQueryWrapper.eq("vege_id", vegeId);
        putClientQueryWrapper.eq("client_id", clientId);
        putClientQueryWrapper.orderByDesc("put_validtime");
        List<PutClient> putClients = putClientMapper.selectList(putClientQueryWrapper);
        Integer quotationPeriod = user.getQuotationPeriod();
        if (quotationPeriod != null && quotationPeriod >= 0 &&
                CollUtil.isNotEmpty(putClients) && isPutAway(putClients.get(0), quotationPeriod)) {
            // 未过期时重复上架，只刷新库存
            jkAsyncService.asyncUpdateStock(vegeId);
            log.debug("商品已上架且未过期，只进行异步刷新库存");
            return;
        }

        // 计算/获取上架价格
        DefaultData defaultData = defaultDataMapper.selectByUid(clientId);
        WjProductOffer wjProductOffer = wjProductOfferMapper.selectById(wjProductOfferId);
        BigDecimal putOffer = data.getPutOffer();
        if (putOffer == null) {
            if (defaultData == null || defaultData.getGross() == null
                    || defaultData.getDiscount() == null || defaultData.getBusinessExpense() == null) {
                throw new DatabaseException(DEFAULT_DATA_LOST);
            }

            //  成本/（1-利润率）* (1+商务费)
            putOffer = baseClient.getOffer()
                    .multiply(BigDecimal.valueOf(100).add(defaultData.getBusinessExpense()))
                    .divide(BigDecimal.valueOf(100).subtract(defaultData.getGross()), BIG_DECIMAL_SCALE, RoundingMode.HALF_UP);
        } else {
            putOffer = putOffer.setScale(BIG_DECIMAL_SCALE, RoundingMode.HALF_UP);
        }

        // 构建上架数据
        PutClient putClient = new PutClient();
        putClient.setWjProductOfferId(wjProductOfferId);
        putClient.setClientId(clientId);
        putClient.setBaseId(baseClient.getBaseId());
        putClient.setOffer(baseClient.getOffer());
        putClient.setVegeId(vegeId);
        putClient.setRealVegeid(baseClient.getRealVegeid());
        putClient.setCost(baseClient.getCost());
        putClient.setGross(Optional.ofNullable(defaultData)
                .map(DefaultData::getGross)
                .map(BigDecimal::toPlainString)
                .orElse(DEFAULT_DATA_LOST));
        putClient.setDiscount(Optional.ofNullable(defaultData)
                .map(DefaultData::getDiscount)
                .map(BigDecimal::toPlainString)
                .orElse(DEFAULT_DATA_LOST));
        putClient.setBusinessExpense(Optional.ofNullable(defaultData)
                .map(DefaultData::getBusinessExpense)
                .map(BigDecimal::toPlainString)
                .orElse(DEFAULT_DATA_LOST));
        putClient.setPutOffer(putOffer);
        Optional<WjProductOffer> op = Optional.of(wjProductOffer);
        putClient.setPutValidtime(op.map(WjProductOffer::getAddTime).orElse(0) * 1000L +
                op.map(WjProductOffer::getValidityDay).orElse(0) * DAY2MILLIS);
        putClient.setComment(baseClient.getComment());
        putClient.setPutDate(new Date());
        putClientMapper.insert(putClient);

        // 上报与数据推送
        BigDecimal price = containYuanPerOne ? putOffer :
                putOffer.divide(BigDecimal.valueOf(1000), BIG_DECIMAL_SCALE, RoundingMode.HALF_UP);
        List<UserVege> list = jkService.getList(clientId);
        if (list.stream()
                .map(UserVege::getProductId)
                .anyMatch(vegeId::equals)) {
            jkService.updateVegePrice(clientId, vegeId, wjProductOffer.getSuk(), price);
        } else {
            try {
                jkService.addUserVege(clientId, vegeId);
                jkService.updateVegePrice(clientId, vegeId, wjProductOffer.getSuk(), price);
            } catch (Exception e) {
                jkService.deleteUserVege(clientId, vegeId);
                throw e;
            }
        }

        // 异步刷新库存
        jkAsyncService.asyncUpdateStock(vegeId);
    }

    private boolean isPutAway(PutClient putClient, Integer quotationPeriod) {
        Long uid = putClient.getClientId();
        Long productId = putClient.getVegeId();
        List<UserVege> list = jkService.getList(uid);
        long current = new Date().getTime();
        long day = (current - putClient.getPutDate().getTime()) / DAY2MILLIS;
        if (day * DAY2MILLIS < current - putClient.getPutDate().getTime()) {
            day++;
        }
        return list.stream()
                .anyMatch(uv -> Objects.equals(uv.getProductId(), productId)) &&
                day < quotationPeriod;
    }

    @Override
    public int insertOffer(BaseClient baseClient) {
        /*Long baseId = baseClient.getBaseId();
        Long clientId = baseClient.getClientId();
        Long vegeId = baseClient.getVegeId();
        String cost = baseClient.getCost();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("vege_id", vegeId);
        queryWrapper.eq("base_id", baseId);
        queryWrapper.eq("client_id", clientId);
        queryWrapper.eq("cost", cost);
        List<BaseClient> list = mapper.selectList(queryWrapper);
        if (list.size() != 0) {
            for (BaseClient client : list) {
                Long id = client.getId();
                mapper.deleteById(id);
            }
        }*/
        int insert = mapper.insert(baseClient);
        if (insert == 0) {
            throw new ControllerException("插入报价失败");
        }
        return insert;
    }


}
